package ru.innoconsulting.building;

import java.security.Principal;
import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.vaadin.Application;
import com.vaadin.service.ApplicationContext;
import com.vaadin.service.ApplicationContext.TransactionListener;
import com.vaadin.terminal.ExternalResource;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.Window;

public class AppengineauthApplication extends Application {
	private static final long serialVersionUID = 1108466519494665064L;

	private static HashMap<ApplicationContext, TransactionListener> requestListeners = new HashMap<ApplicationContext, TransactionListener>();

	private Window mainWindow;

	private boolean isInitialized = false;

	private HorizontalLayout authInfo;

	@Override
	public void init() {
		// Only add one listener per context as Vaadin calls every listener in
		// the context for every request.
		if (getContext() != null && requestListeners.get(getContext()) == null) {
			TransactionListener listener = new TransactionListener() {
				private static final long serialVersionUID = -8490216576436646032L;

				@Override
				public void transactionStart(Application app, Object req) {
					if (!isInitialized) {
						buildUI();
						isInitialized = true;
					}

					checkLoginLogout((HttpServletRequest) req);
				}

				@Override
				public void transactionEnd(Application app, Object req) {
					// NOP
				}
			};

			getContext().addTransactionListener(listener);

			requestListeners.put(getContext(), listener);
		}
	}

	private synchronized void buildUI() {
		setMainWindow(mainWindow = new Window(
				"Google accounts authentication on GAE"));

		mainWindow
				.addComponent(new Label(
						"Demonstrating how to do Google accounts authentication in a <a href=\"http://www.vaadin.com\">Vaadin</a> application deployed to Google App Engine.",
						Label.CONTENT_XHTML));

		// Add a layout that will contain user's email and login/logout link.
		mainWindow.addComponent(authInfo = new HorizontalLayout());

		authInfo.setSpacing(true); // Awfully crowded without this...
	}

	private void checkLoginLogout(HttpServletRequest request) {
		Principal user = request.getUserPrincipal();

		if (authInfo.getComponentIterator().hasNext()
				&& ((user != null && getUser() != null) || (user == null && getUser() == null))) {
			return; // Layout initialized, and no login/logout detected
		}

		UserService userService = UserServiceFactory.getUserService();

		Link link;
		Label email;
		if (request.getUserPrincipal() != null) {
			// Login detected, store user email to application
			setUser(request.getUserPrincipal().getName());

			if (userService.isUserAdmin()) {
				mainWindow.showNotification("You have admin privileges");
			}

			mainWindow.showNotification("Hello "
					+ request.getUserPrincipal().getName());

			email = new Label(request.getUserPrincipal().getName());
			link = new Link("logout", new ExternalResource(userService
					.createLogoutURL(request.getRequestURI())));
		} else {
			// Logout detected, or application initialized without login info
			if (getUser() != null) {
				mainWindow.showNotification("Bye " + getUser().toString());
			}

			setUser(null);

			email = new Label("anonymous");
			link = new Link("login", new ExternalResource(userService
					.createLoginURL(request.getRequestURI())));
		}

		authInfo.removeAllComponents();

		email.setStyleName("email");
		authInfo.addComponent(email);

		authInfo.addComponent(link);
	}
}
